package cn.com.code.generator.utils;

import cn.com.code.generator.entity.system.AssertInfo;
import cn.com.code.generator.entity.system.ColumnInfo;
import cn.com.code.generator.entity.system.GenInfo;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 代码生成器   工具类
 *
 * @author chenshun
 * @email sunlightcs@gmail.com
 * @date 2016年12月19日 下午11:40:24
 */
@Component
public abstract class AbstractGenUtils {

    @Autowired
    private JdbcUtil jdbcUtil;

    public static List<String> getTemplates(){
        List<String> templates = new ArrayList<String>();
        templates.add("template/system/Entity.java.vm");
        templates.add("template/system/Dao.java.vm");
        templates.add("template/system/Dao.xml.vm");
        templates.add("template/system/Service.java.vm");
        templates.add("template/system/ServiceImpl.java.vm");
        templates.add("template/system/Controller.java.vm");

        templates.add("template/system/menu.mysql.sql.vm");
        templates.add("template/system/menu.oracle.sql.vm");

        templates.add("template/system/elementui/index.vue.vm");
        templates.add("template/system/elementui/index.js.vm");
        templates.add("template/system/elementui/api.js.vm");
        templates.add("template/system/elementui/add.vue.vm");
        templates.add("template/system/elementui/detail.vue.vm");

        return templates;
    }

    /**
     * 生成代码
     */
    public void generatorCode(GenInfo genInfo, ZipOutputStream zip) {
        //设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader" );
        Velocity.init(prop);

        if(genInfo.getColumnList().size()>0){
            genInfo.getColumnList().get(genInfo.getColumnList().size()-1).setLastOne(true);
        }
        //封装模板数据
        Map<String, Object> map = getDataMap(genInfo);

        VelocityContext context = new VelocityContext(map);

        //获取模板列表
        List<String> templates = getTemplates();
        for (String template : templates) {
            //渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, "UTF-8" );
            tpl.merge(context, sw);
            try {
                //添加到zip genInfo.getTable().getPkgName()
                zip.putNextEntry(new ZipEntry(getFileName(template, genInfo.getTable().getClsName(), genInfo.getTable().getPkgName(), genInfo.getTable().getModuleName())));
                IOUtils.write(sw.toString(), zip, "UTF-8" );
                IOUtils.closeQuietly(sw);
                zip.closeEntry();
            } catch (IOException e) {
                throw new RRException("渲染模板失败，表名：" + genInfo.getTable().getTableName(), e);
            }
        }
    }

    /**
     * 封装模板数据
     * @param genInfo
     * @return
     */
    public Map<String, Object> getDataMap(GenInfo genInfo) {
        //配置信息
        Configuration config = getConfig();
        //封装模板数据
        Map<String, Object> map = new HashMap<>();
        map.put("tableName", genInfo.getTable().getTableName());
        map.put("toExcel", genInfo.getTable().getToExcel());
        map.put("comments", genInfo.getTable().getComments());
        map.put("pk", genInfo.getTable().getPkEntity(genInfo.getColumnList()));
        map.put("className", genInfo.getTable().getClsName());
        map.put("classname", genInfo.getTable().getClsname());
        map.put("pathName", genInfo.getTable().getPathName());
        //封装jdbcType
        genInfo.getColumnList().forEach(col -> col.setJdbcType(jdbcUtil.getJdbcType(col.getJavaType())));
        map.put("columns", genInfo.getColumnList());
        map.put("mainPath", "cn.com.code.dsf");
        map.put("package", genInfo.getTable().getPkgName());
        map.put("moduleName", genInfo.getTable().getModuleName());
        map.put("author", config.getString("author" ));
        map.put("email", config.getString("email" ));
        map.put("datetime", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
        map.put("assertInfo", new AssertInfo(genInfo));

        //搜索关键字
        ColumnInfo searchColumn = null;
        for(ColumnInfo columnInfo : genInfo.getColumnList()){
            if("true".equals(columnInfo.getWhere())){
                searchColumn = columnInfo;
                break;
            }
        }
        map.put("searchColumn", searchColumn);
        return map;
    }

    /**
     * 列名转换成Java属性名
     */
    public String columnToJava(String columnName) {
        return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "" );
    }

    /**
     * 表名转换成Java类名
     */
    public String tableToJava(String tableName, String tablePrefix) {
        if (StringUtils.isNotBlank(tablePrefix)) {
            tableName = tableName.replace(tablePrefix, "" );
        }
        return columnToJava(tableName);
    }

    /**
     * 获取配置信息
     */
    public Configuration getConfig() {
        try {
            return new PropertiesConfiguration("generator.properties" );
        } catch (ConfigurationException e) {
            throw new RRException("获取配置文件失败，", e);
        }
    }

    /**
     * 获取文件名
     */
    public abstract String getFileName(String template, String className, String packageName, String moduleName);
}
